Skip to content

Conversation

@Smirl
Copy link

@Smirl Smirl commented Nov 18, 2025

Description: (required)

Fixes #1438

This pull request adds support for a new $length operator in the ConditionalRouter service, allowing conditional routing logic to evaluate the length of arrays. This enhancement makes it possible to write more expressive and flexible conditions based on array length, including direct comparisons or using other operators like $gt or $lt on the length.

New Operator Support:

  • Added Length ($length) to the Operator enum in conditionalRouter.ts to enable length-based conditions.

Conditional Evaluation Logic:

  • Implemented logic in ConditionalRouter to handle the $length operator, supporting both direct numeric comparisons and nested operator objects (e.g., { $gt: 5 }) for array lengths.

Tests Run/Test cases added: (required)

  • Tests for all conditional operators

Type of Change:

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update
  • Refactoring (no functional changes)

Smirl and others added 2 commits November 18, 2025 10:02
- Test basic equality matching with $length
- Test nested operators ($gt, $lt, $gte, $lte, $eq, $ne)
- Test edge cases (empty arrays, non-arrays, metadata arrays)
- Test complex conditional queries with $and
- Add regression tests for existing operators
- All 16 tests passing

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
@narengogi
Copy link
Collaborator

@Smirl could you add a few examples on how you're using this new parameter in config?

@Smirl
Copy link
Author

Smirl commented Nov 19, 2025

I was trying to create a workaround whilst waiting for #1429. Then I noticed there wasn't a length or size operator so I added it. It won't help me on this occasion but being able to look at array types might be useful.

{
  "strategy": {
    "mode": "conditional",
    "conditions": [
      {
        "query": {
          "params.tools": {
            "$length": 0
          }
        },
        "then": "default-tool-router"
      }
    ],
    "default": "model-router"
  },
  "targets": [
    {
      "name": "model-router",
      "retry": {
        "attempts": 3
      },
      "cache": {
        "mode": "simple"
      },
      "override_params": {
        "model": "@bedrock-sandbox/eu.anthropic.claude-sonnet-4-5-20250929-v1:0"
      }
    },
    {
      "name": "default-tool-router",
      "retry": {
        "attempts": 3
      },
      "cache": {
        "mode": "simple"
      },
      "override_params": {
        "model": "@bedrock-sandbox/eu.anthropic.claude-sonnet-4-5-20250929-v1:0",
        "tools": [
          {
            "type": "function",
            "function": {
              "name": "noop",
              "description": "never call this tool",
              "input_schema": {
                "type": "object"
              }
            }
          }
        ]
      }
    }
  ]
}

@roh26it roh26it requested a review from Copilot November 21, 2025 07:22
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR introduces a $length operator to the ConditionalRouter service, enabling conditional routing decisions based on array length. The operator supports both direct numeric comparisons (e.g., $length: 3) and nested operator expressions (e.g., $length: { $gt: 5 }), allowing flexible array length-based routing logic.

Key Changes:

  • Added Length ($length) to the Operator enum
  • Implemented evaluation logic for the $length operator with support for nested operators
  • Added comprehensive test coverage for various $length usage patterns

Reviewed Changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
src/services/conditionalRouter.ts Added $length operator to enum and implemented evaluation logic with nested operator support
tests/unit/src/services/conditionalRouter.test.ts Added comprehensive test suite covering direct length matching, nested operators, edge cases, and complex queries

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

if (!Array.isArray(value)) return false;
// compareValue could be a number or an object like {$gt: 5}
if (typeof compareValue === 'number') {
if (value.length !== compareValue) return false;
Copy link

Copilot AI Nov 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] The direct numeric comparison using inequality (value.length !== compareValue) could be simplified by leveraging the existing operator evaluation logic. Consider using !this.evaluateOperator({ [Operator.Eq]: compareValue }, value.length) to maintain consistency with the nested operator path and reduce code duplication.

Suggested change
if (value.length !== compareValue) return false;
if (!this.evaluateOperator({ [Operator.Equal]: compareValue }, value.length)) return false;

Copilot uses AI. Check for mistakes.
} else if (
typeof compareValue === 'object' &&
compareValue !== null
) {
Copy link

Copilot AI Nov 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The condition checks if compareValue is an object and not null, but doesn't validate that it contains valid operator keys. Consider adding validation to ensure compareValue is a valid operator object before recursively evaluating, or handle the case where it might be an unexpected object type.

Suggested change
) {
) {
// Validate that compareValue contains at least one valid operator key before recursion
const validOperators = [
Operator.Equal,
Operator.NotEqual,
Operator.GreaterThan,
Operator.GreaterThanOrEqual,
Operator.LessThan,
Operator.LessThanOrEqual,
Operator.In,
Operator.NotIn,
Operator.Regex,
Operator.Length
];
const hasValidOperatorKey = Object.keys(compareValue).some((key) =>
validOperators.includes(key as Operator)
);
if (!hasValidOperatorKey) {
// Handle unexpected object type
return false;
}

Copilot uses AI. Check for mistakes.
@roh26it
Copy link
Collaborator

roh26it commented Nov 21, 2025

Hi @Smirl, while #1429 has been merged and released, this PR is still valuable. We'll review it

@Smirl
Copy link
Author

Smirl commented Nov 21, 2025

@roh26it thanks. Let me know if you want anything else from me.

Looks like #1429 isn't released yet as the last release was 2 weeks ago. https://github.com/Portkey-AI/gateway/releases

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature] Add length conditional operator

3 participants